MessagePacker - some Rust in the msgpack protocol
The protocol specification can be found here.
This crate targets simplicity and performance. No dependencies are used, just the standard Rust library.
We have two main structures available:
- Message - Owned parsed values
- MessageRef - Message parsed by reference and bound to the lifetime of the readers source
For convenience, a derive macro is available to implement Packable
and Unpackable
for the types. These implementations will allow the types to be sent and received from MessagePacker
and MessageUnpacker
implementations. If the feature impl-io
is enabled, these traits will be automatically implemented for instances of io::{Read, Write}
.
Example
use *;
use io;
let bar = Bar ;
let foo = Foo ;
// Create a new bytes buffer
let mut buffer: = vec!;
// Pack the message into the buffer
//
// Provided the feature `impl-io` is activated, `io::Cursor` will extend `MessagePacker` since it implements `io::Write`
new.pack.expect;
// Unpack the message from the buffer
//
// Provided the feature `impl-io` is activated, `io::Cursor` will extend `MessageUnpacker` since it implements `io::Read`
let foo_p = new..expect;
// Assert the unpacked message is exactly the same as the original
assert_eq!;
Example of manual implementation
use *;
use ;
let buffer = vec!;
let mut cursor = new;
let key = string;
let value = integer_signed;
let entry = new;
let message = map;
// Write the message to the cursor
message.pack.expect;
cursor.rewind.expect;
// Read the message from the cursor
let restored = unpack.expect;
let value = restored
.as_map
.expect
.first
.expect
.val
.as_integer
.expect
.as_i64
.expect;
assert_eq!;
// Alternatively, we can use the index implementation
let value = restored
.as_integer
.expect
.as_i64
.expect;
assert_eq!;
Example (by ref)
use *;
use ;
let mut cursor = new;
let key = String;
let value = Integer;
let entry = new;
let message = Map;
// Write the message to the cursor
message.pack.expect;
cursor.rewind.expect;
// The consumer need to guarantee himself the cursor source will live long enough to satisfy the
// lifetime of the message reference.
//
// If this is guaranteed, then the function is safe.
let restored = unsafe ;
// The lifetime of `MessageRef` is not bound to the `Read` implementation because the source
// might outlive it - as in this example
let _buffer = cursor.into_inner;
// `MessageRef` behaves the same as `Message`, but the runtime cost is cheaper because it will
// avoid a couple of unnecessary copies
let value = restored
.as_map
.expect
.first
.expect
.val
.as_integer
.expect
.as_i64
.expect;
assert_eq!;
// MessageRef also implements `Index`
let value = restored
.as_integer
.expect
.as_i64
.expect;
assert_eq!;
Benchmarks
Results obtained with Intel(R) Core(TM) i9-9900X CPU @ 3.50GHz
. To generate benchmarks, run $ cargo bench
.
The benchmark compares msgpacker with two very popuplar Rust implementations: rmpv and rmps. The performance was similar for pack and unpack, with msgpacker taking the lead a couple of times. Very often rmps was far behind.
The performance of integer packing was better for msgpacker.
However, for unpack by reference, the performance was dramatically better in favor of msgpacker for map deserialization.
The full report can be found here.